//
// Created by YE on 2024/1/7.
//
#include "parser.h"
#include "coder.h"

Parser::Parser(Lexer *lexer) {
    this->lexer = lexer;
    this->lexer->get_next_Token(&current_token);
    cs = {ENONE, 0,
          YCH_VM_I_START, YCH_VM_FUNC_START, 0, 0, 1,  0, 0, false};
}

Parser::~Parser() = default;


Parser_State Parser::parse() {
    if (!syn.empty()) return PARSER_ERROR;
    if (current_token.type == TK_EOF) return PARSER_END;
    T x;
    syn.push(NT_S);
    while (!syn.empty()) {
        x = syn.top();
        syn.pop();
        if (x < FIRST_NT) {
            if (x == current_token.type) {
                lexer->get_next_Token(&current_token);
            } else {
                if (current_token.type != TK_ILLEGAL)
                    throw_error(YCH_PARSER_ERROR, error_string(SYN_ERROR));
                return PARSER_ERROR;
            }
        } else if (x < FIRST_ACTION) {
            if (deduce(x, current_token.type, &syn)) {
                if (current_token.type != TK_ILLEGAL)
                    throw_error(YCH_PARSER_ERROR, error_string(SYN_ERROR));
                return PARSER_ERROR;
            }
        } else {
            Sem_State s = operate(this, x);
            if (s) {
                throw_error(YCH_PARSER_ERROR, error_string(s));
                return PARSER_ERROR;
            }
        }
    }
    return PARSER_OK;
}


const T P_S1[] = {NT_DS};
const T P_S2[] = {NT_FS};
const T P_S3[] = {NT_RS};
const T P_S4[] = {';'};
const T P_S5[] = {NT_ES};
const T P_S6[] = {NT_IS};
const T P_S7[] = {NT_WS};
const T P_S8[] = {NT_BS};
const T P_S9[] = {NT_CS};
const T P_S10[] = {NT_DELS};

const T P_DS[] = {AC_SET_EKIND, NT_DTYPE, NT_DL, ';'};

const T P_DTYPE1[] = {TK_INT};
const T P_DTYPE2[] = {TK_FLOAT};
const T P_DTYPE3[] = {TK_STRING};
const T P_DTYPE4[] = {TK_MAT};//TODO NT_E
const T P_DTYPE5[] = {TK_BOOL};

const T P_DL[] = {AC_MALLOC_VAR, TK_NAME, NT_DA, NT_DF};

const T P_DA1[] = {'=', NT_DV, AC_ASSIGN_FIRST};
const T P_DA2[] = {AC_SEM_POP};
const T P_NT_DF[] = {',', NT_DL};

const T P_NT_DV1[] = {NT_E10};//TODO NT_E
const T P_NT_DV2[] = {NT_MAT_V};

const T P_NT_MAT_V[] = {AC_MAT_START, '{', NT_MAT_V_IN, '}', AC_MAT_END};

const T P_NT_MAT_V_IN[] = {'{', NT_MAT_V_IN_IN, '}', AC_MAT_COUNT_ROW, NT_MAT_V_1_LIST};

const T P_NT_MAT_V_1_LIST[] = {',', NT_MAT_V_IN};

const T P_NT_MAT_V_IN_IN[] = {NT_E4, AC_MAT_COUNT_COL, NT_MAT_V_2_LIST};//TODO NT_E

const T P_NT_MAT_V_2_LIST[] = {',', NT_MAT_V_IN_IN};

const T P_NT_FS[] = {TK_FUNCTION, AC_DEF_FUNC_START, TK_NAME, '(', NT_FS_PARAM_LIST, ')', NT_CS,
                     AC_DEF_FUNC_END};//TODO FR

const T P_NT_FS_PARAM_LIST[] = {AC_DEF_COUNT_PARAMS, TK_NAME, NT_FS_PARAM_LIST_F};

const T P_NT_FS_PARAM_LIST_F[] = {',', NT_FS_PARAM_LIST};

const T P_NT_S_LIST[] = {NT_S, NT_S_LIST};

const T P_NT_RS[] = {TK_RETURN, NT_R_F, AC_RETURN, ';'};

const T P_NT_R_F[] = {NT_E10};//TODO NE

const T P_NT_ES[] = {NT_E10, ';', AC_POP};//TODO NE

const T P_NT_E10[] = {NT_E9, NT_E10_F};
const T P_NT_E10_F[] = {'=', NT_E9, AC_PUSH_ASSIGN, NT_E10_F};
const T P_NT_E10_F1[] = {AC_SEM_ASSIGN_END};

const T P_NT_E9[] = {NT_E8, NT_E9_F};
const T P_NT_E9_F[] = {'|', NT_E8, AC_OR, NT_E9_F};

const T P_NT_E8[] = {NT_E7, NT_E8_F};
const T P_NT_E8_F[] = {'&', NT_E7, AC_AND, NT_E8_F};

const T P_NT_E7[] = {NT_E6};
const T P_NT_E7_1[] = {'!', NT_E7, AC_NOT};

const T P_NT_E6[] = {NT_E5, NT_E6_F};
const T P_NT_E6_F1[] = {TK_EQUAL, NT_E5, AC_EQUAL, NT_E6_F};
const T P_NT_E6_F2[] = {TK_NOTEQUAL, NT_E5, AC_NOTEQUAL, NT_E6_F};

const T P_NT_E5[] = {NT_E4, NT_E5_F};
const T P_NT_E5_F1[] = {'<', NT_E4, AC_LESS, NT_E5_F};
const T P_NT_E5_F2[] = {'>', NT_E4, AC_GREATER, NT_E5_F};
const T P_NT_E5_F3[] = {TK_LESSEQUAL, NT_E4, AC_LESSEQUAL, NT_E5_F};
const T P_NT_E5_F4[] = {TK_GREATEREQUAL, NT_E4, AC_GREATEREQUAL, NT_E5_F};

const T P_NT_E4[] = {NT_E3, NT_E4_F};
const T P_NT_E4_F1[] = {'+', NT_E3, AC_ADD, NT_E4_F};
const T P_NT_E4_F2[] = {'-', NT_E3, AC_SUB, NT_E4_F};

const T P_NT_E3[] = {NT_E2, NT_E3_F};
const T P_NT_E3_F1[] = {'*', NT_E2, AC_MUL, NT_E3_F};
const T P_NT_E3_F2[] = {'/', NT_E2, AC_DIV, NT_E3_F};
const T P_NT_E3_F3[] = {'%', NT_E2, AC_MOD, NT_E3_F};
const T P_NT_E3_F4[] = {TK_INNER, NT_E2, AC_INNER, NT_E3_F};

const T P_NT_E2[] = {NT_E1};
const T P_NT_E2_1[] = {'+', NT_E1};
const T P_NT_E2_2[] = {'-', NT_E1, AC_NEG};

const T P_NT_E1[] = {NT_F, NT_E1_F};
const T P_NT_E1_F[] = {TK_POW, NT_F, AC_POW, NT_E1_F};

const T P_NT_F1[] = { TK_NAME, NT_F_F};
const T P_NT_F2[] = {AC_PUSH_CONST, NT_F_CONST};
const T P_NT_F3[] = {'(', NT_E10, ')'};//TODO NT_E

const T P_NT_F_CONST1[] = {TK_INT_V};
const T P_NT_F_CONST2[] = {TK_FLOAT_V};
const T P_NT_F_CONST3[] = {TK_STRING_V};
const T P_NT_F_CONST4[] = {TK_TRUE};
const T P_NT_F_CONST5[] = {TK_FALSE};

const T P_NT_F_F1[] = {AC_SEM_PUSH_VAR, NT_F_F_F};
const T P_NT_F_F2[] = {AC_SEM_PUSH_FUNC, '(', NT_F_PARAM_LIST, ')', AC_FUNC_END};

const T P_NT_F_F_F[] = {'[', NT_E10, ']', AC_INDEX, NT_F_F_F};//TODO NT_E

const T P_NT_F_PARAM_LIST[] = {NT_E10, AC_FUNC_COUNT_PARAM, NT_F_PARAM_LIST_F};//TODO NT_E
const T P_NT_F_PARAM_LIST_F[] = {',', NT_F_PARAM_LIST};

const T P_NT_IS[] = {TK_IF, '(', NT_E10, ')', AC_IF_JUDGE, NT_S, NT_IS_ELSE};
const T P_NT_IS_ELSE[] = {TK_ELSE, AC_PUSH_ELSE, NT_S, AC_ELSE_END};
const T P_NT_IS_ELSE1[] = {AC_IF_END};

const T P_NT_WS[] = {TK_WHILE, AC_PUSH_WHILE, '(', NT_E10, ')', AC_WHILE_JUDGE, NT_S, AC_WHILE_END};

const T P_NT_BS[] = {TK_BREAK, AC_BREAK, ';'};

const T P_NT_CS[] = {'{', NT_S_LIST, '}'};

const T P_NT_DELS[] = {TK_DEL, TK_NAME, NT_DELS_F, ';'};
const T P_NT_DELS_F[] = {',', TK_NAME, NT_DELS_F};

#define pushM(p, s) pushR(p,(sizeof p)/(sizeof (unsigned int))-1,s);return SYN_OK
#define pushV() return SYN_OK

static Syn_State deduce(T x, T w, std::stack<T> *stack) {
    switch (x) {
        case NT_S:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                pushM(P_S5, stack);//NT_E
                case TK_INT:
                case TK_FLOAT:
                case TK_STRING:
                case TK_MAT:
                case TK_BOOL:
                pushM(P_S1, stack);
                case TK_FUNCTION:
                pushM(P_S2, stack);
                case TK_RETURN:
                pushM(P_S3, stack);
                case TK_IF:
                pushM(P_S6, stack);
                case TK_WHILE:
                pushM(P_S7, stack);
                case TK_BREAK:
                pushM(P_S8, stack);
                case '{':
                pushM(P_S9, stack);
                case ';':
                pushM(P_S4, stack);
                case TK_DEL:
                pushM(P_S10, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_ES:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                pushM(P_NT_ES, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_E10:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                pushM(P_NT_E10, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_E10_F:
            switch (w) {
                //TODO follow 集合E9
                case ')':
                case ']':
                case '}':
                case ',':
                case ';':
                pushM(P_NT_E10_F1, stack);
                case '=':
                pushM(P_NT_E10_F, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_E9:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                pushM(P_NT_E9, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_E9_F:
            switch (w) {
                case ';'://TODO follow 集合E8
                case ')':
                case ']':
                case '}':
                case ',':
                case '=':
                    pushV();
                case '|':
                pushM(P_NT_E9_F, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_E8:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                pushM(P_NT_E8, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_E8_F:
            switch (w) {
                case ';'://TODO follow 集合E7
                case ')':
                case ']':
                case '}':
                case ',':
                case '|':
                case '=':
                    pushV();
                case '&':
                pushM(P_NT_E8_F, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_E7:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                pushM(P_NT_E7, stack);
                case '!':
                pushM(P_NT_E7_1, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_E6:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                pushM(P_NT_E6, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_E6_F:
            switch (w) {
                case ';'://TODO follow 集合E6
                case ')':
                case ']':
                case '}':
                case ',':
                case '&':
                case '|':
                case '=':
                    pushV();
                case TK_EQUAL:
                pushM(P_NT_E6_F1, stack);
                case TK_NOTEQUAL:
                pushM(P_NT_E6_F2, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_E5:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                pushM(P_NT_E5, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_E5_F:
            switch (w) {
                case ';'://TODO follow 集合E5
                case ')':
                case ']':
                case '}':
                case ',':
                case TK_EQUAL:
                case TK_NOTEQUAL:
                case '&':
                case '|':
                case '=':
                    pushV();
                case '<':
                pushM(P_NT_E5_F1, stack);
                case '>':
                pushM(P_NT_E5_F2, stack);
                case TK_LESSEQUAL:
                pushM(P_NT_E5_F3, stack);
                case TK_GREATEREQUAL:
                pushM(P_NT_E5_F4, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_E4:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                pushM(P_NT_E4, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_E4_F:
            switch (w) {
                case ';'://TODO follow 集合E4
                case ')':
                case ']':
                case '}':
                case ',':
                case '<':
                case '>':
                case TK_LESSEQUAL:
                case TK_GREATEREQUAL:
                case TK_EQUAL:
                case TK_NOTEQUAL:
                case '&':
                case '|':
                case '=':
                    pushV();
                case '+':
                pushM(P_NT_E4_F1, stack);
                case '-':
                pushM(P_NT_E4_F2, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_E3:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                pushM(P_NT_E3, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_E3_F:
            switch (w) {
                case ';'://TODO follow 集合E3
                case ')':
                case ']':
                case '}':
                case ',':
                case '+':
                case '-':
                case '<':
                case '>':
                case TK_LESSEQUAL:
                case TK_GREATEREQUAL:
                case TK_EQUAL:
                case TK_NOTEQUAL:
                case '&':
                case '|':
                case '=':
                    pushV();
                case '*':
                pushM(P_NT_E3_F1, stack);
                case '/':
                pushM(P_NT_E3_F2, stack);
                case '%':
                pushM(P_NT_E3_F3, stack);
                case TK_INNER:
                pushM(P_NT_E3_F4, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_E2:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                pushM(P_NT_E2, stack);
                case '+':
                pushM(P_NT_E2_1, stack);
                case '-':
                pushM(P_NT_E2_2, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_E1:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                pushM(P_NT_E1, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_E1_F:
            switch (w) {
                case ';'://TODO follow 集合E1
                case ')':
                case ']':
                case '}':
                case ',':
                case '+':
                case '-':
                case '*':
                case '/':
                case '%':
                case TK_INNER:
                case '<':
                case '>':
                case TK_LESSEQUAL:
                case TK_GREATEREQUAL:
                case TK_EQUAL:
                case TK_NOTEQUAL:
                case '&':
                case '|':
                case '=':
                    pushV();
                case TK_POW:
                pushM(P_NT_E1_F, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_F:
            switch (w) {
                case TK_NAME:
                pushM(P_NT_F1, stack);
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                pushM(P_NT_F2, stack);
                case '(':
                pushM(P_NT_F3, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_F_F:
            switch (w) {
                case '(':
                pushM(P_NT_F_F2, stack);
                case '['://TODO follow 集合F_F
                case ';':
                case ')':
                case ']':
                case '}':
                case ',':
                case TK_POW:
                case '*':
                case '/':
                case '%':
                case TK_INNER:
                case '+':
                case '-':
                case '<':
                case '>':
                case TK_LESSEQUAL:
                case TK_GREATEREQUAL:
                case TK_EQUAL:
                case TK_NOTEQUAL:
                case '&':
                case '|':
                case '=':
                pushM(P_NT_F_F1, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_F_F_F:
            switch (w) {
                case '[':
                pushM(P_NT_F_F_F, stack);
                case ';'://TODO follow 集合F_F_F
                case ')':
                case ']':
                case '}':
                case ',':
                case TK_POW:
                case '*':
                case '/':
                case '%':
                case TK_INNER:
                case '+':
                case '-':
                case '<':
                case '>':
                case TK_LESSEQUAL:
                case TK_GREATEREQUAL:
                case TK_EQUAL:
                case TK_NOTEQUAL:
                case '&':
                case '|':
                case '=':
                    pushV();
                default:
                    return SYN_ERROR;
            }
        case NT_F_PARAM_LIST:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                pushM(P_NT_F_PARAM_LIST, stack);
                case ')':
                    pushV();
                default:
                    return SYN_ERROR;
            }
        case NT_F_PARAM_LIST_F:
            switch (w) {
                case ',':
                pushM(P_NT_F_PARAM_LIST_F, stack);
                case ')':
                    pushV();
                default:
                    return SYN_ERROR;
            }
        case NT_F_CONST:
            switch (w) {
                case TK_INT_V:
                pushM(P_NT_F_CONST1, stack);
                case TK_FLOAT_V:
                pushM(P_NT_F_CONST2, stack);
                case TK_STRING_V:
                pushM(P_NT_F_CONST3, stack);
                case TK_TRUE:
                pushM(P_NT_F_CONST4, stack);
                case TK_FALSE:
                pushM(P_NT_F_CONST5, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_DS:
            switch (w) {
                case TK_INT:
                case TK_FLOAT:
                case TK_STRING:
                case TK_MAT:
                case TK_BOOL:
                pushM(P_DS, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_DTYPE:
            switch (w) {
                case TK_INT:
                pushM(P_DTYPE1, stack);
                case TK_FLOAT:
                pushM(P_DTYPE2, stack);
                case TK_STRING:
                pushM(P_DTYPE3, stack);
                case TK_MAT:
                pushM(P_DTYPE4, stack);
                case TK_BOOL:
                pushM(P_DTYPE5, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_DL:
            switch (w) {
                case TK_NAME:
                pushM(P_DL, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_DA:
            switch (w) {
                case '=':
                pushM(P_DA1, stack);
                case ';':
                case ',':
                pushM(P_DA2, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_DV:
            switch (w) {
                case '{':
                pushM(P_NT_DV2, stack);
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                pushM(P_NT_DV1, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_DF:
            switch (w) {
                case ';':
                    pushV();
                case ',':
                pushM(P_NT_DF, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_MAT_V:
            switch (w) {
                case '{':
                pushM(P_NT_MAT_V, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_MAT_V_IN:
            switch (w) {
                case '{':
                pushM(P_NT_MAT_V_IN, stack);
                case '}':
                    pushV();
                default:
                    return SYN_ERROR;
            }
        case NT_MAT_V_1_LIST:
            switch (w) {
                case ',':
                pushM(P_NT_MAT_V_1_LIST, stack);
                case '}':
                    pushV();
                default:
                    return SYN_ERROR;
            }
        case NT_MAT_V_IN_IN:
            switch (w) {
                case '}':
                    pushV();
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                pushM(P_NT_MAT_V_IN_IN, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_MAT_V_2_LIST:
            switch (w) {
                case '}':
                    pushV();
                case ',':
                pushM(P_NT_MAT_V_2_LIST, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_FS:
            switch (w) {
                case TK_FUNCTION:
                pushM(P_NT_FS, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_FS_R:
            switch (w) {
                case '{':
                    pushV();
                default:
                    return SYN_ERROR;
            }
        case NT_FS_PARAM_LIST:
            switch (w) {
                case TK_NAME:
                pushM(P_NT_FS_PARAM_LIST, stack);
                case ')':
                    pushV();
                default:
                    return SYN_ERROR;
            }
        case NT_FS_PARAM_LIST_F:
            switch (w) {
                case ')':
                    pushV();
                case ',':
                pushM(P_NT_FS_PARAM_LIST_F, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_S_LIST://TODO S2
            switch (w) {
                case '}':
                    pushV();
                case TK_INT:
                case TK_FLOAT:
                case TK_STRING:
                case TK_MAT:
                case TK_BOOL:
                case TK_RETURN:
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                case ';':
                case TK_IF:
                case TK_WHILE:
                case TK_BREAK:
                pushM(P_NT_S_LIST, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_RS:
            switch (w) {
                case TK_RETURN:
                pushM(P_NT_RS, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_R_F:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                pushM(P_NT_R_F, stack);
                case ';':
                    pushV();
                default:
                    return SYN_ERROR;
            }
        case NT_IS:
            switch (w) {
                case TK_IF:
                pushM(P_NT_IS, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_IS_ELSE:
            switch (w) {
                case TK_ELSE:
                pushM(P_NT_IS_ELSE, stack);
                    //TODO IS_ELSE follow
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                case TK_INT:
                case TK_FLOAT:
                case TK_STRING:
                case TK_MAT:
                case TK_BOOL:
                case TK_FUNCTION:
                case TK_RETURN:
                case TK_IF:
                case TK_WHILE:
                case TK_BREAK:
                case '{':
                case ';':
                case TK_DEL:
                case TK_EOF:
                case '}':
                pushM(P_NT_IS_ELSE1, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_WS:
            switch (w) {
                case TK_WHILE:
                pushM(P_NT_WS, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_BS:
            switch (w) {
                case TK_BREAK:
                pushM(P_NT_BS, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_CS:
            switch (w) {
                case '{':
                pushM(P_NT_CS, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_DELS:
            switch (w) {
                case TK_DEL:
                pushM(P_NT_DELS, stack);
                default:
                    return SYN_ERROR;
            }
        case NT_DELS_F:
            switch (w) {
                case ',':
                pushM(P_NT_DELS_F, stack);
                case ';':
                    pushV();
                default:
                    return SYN_ERROR;
            }
        default:
            return SYN_ERROR;
    }
}

static void pushR(const T *production, int s, std::stack<T> *stack) {
    for (; s >= 0; s--) stack->push(production[s]);
}

String Parser::error_string(State st) const {
    size_t file_pos = lexer->reader->line_start_pos, file_end = lexer->reader->pos;
    file_end = lexer->reader->str.find('\n', file_end);
    size_t length = file_end - file_pos;
    std::string s = lexer->reader->str.substr(file_pos, length);
    s.append(" line:" + std::to_string(lexer->reader->line));
    switch (st) {
        case SYN_ERROR:
            s.append(" Syntax Error");
            break;
        case SEM_ERROR:
            s.append(" Sem Error");
            break;
        case SEM_MEM_OVERFLOW_ERROR:
            s.append(" Mem Overflow Error");
            break;
        case SEM_TYPE_ERROR:
            s.append(" Type Error");
            break;
        case SEM_REDECLARATION_VAR_ERROR:
            s.append(" Redeclaration Var Error");
            break;
        case SEM_UNDEFINED_VAR_ERROR:
            s.append(" Undefined Var Error");
            break;
        case SEM_STACK_ERROR:
            s.append(" Stack Error");
            break;
        case SEM_BREAK_NOT_IN_LOOP_STRUCT_ERROR:
            s.append(" Break not in Loop Struct Error");
            break;
        case SEM_UNDEFINED_FUNCTION_ERROR:
            s.append(" Undefined Function Error");
            break;
        case SEM_FUNC_PARAM_ERROR:
            s.append(" Func Params Error");
            break;
        case SEM_REDEF_FUNC_ERROR:
            s.append(" Redefined Func Error");
            break;
        default:
            s.append("ERRER");
    }
    return s;
}


void Parser::load_CLib() {
    load_Clib(&cs);
}
